查看原文
其他

Java面试题全集(12)

2017-03-04 白玉 IT哈哈

111、说一下表达式语言(EL)的隐式对象及其作用。
答:EL的隐式对象包括:pageContext、initParam(访问上下文参数)、param(访问请求参数)、paramValues、header(访问请求头)、headerValues、cookie(访问cookie)、applicationScope(访问application作用域)、sessionScope(访问session作用域)、requestScope(访问request作用域)、pageScope(访问page作用域)。

用法如下所示:

${pageContext.request.method}
${pageContext["request"]["method"]}
${pageContext.request["method"]}
${pageContext["request"].method}
${initParam.defaultEncoding}
${header["accept-language"]}
${headerValues["accept-language"][0]}
${cookie.jsessionid.value}
${sessionScope.loginUser.username}


    补充:表达式语言的.和[]运算作用是一致的,唯一的差别在于如果访问的属性名不符合Java标识符命名规则,例如上面的accept-language就不是一个有效的Java标识符,那么这时候就只能用[]运算符而不能使用.运算符获取它的值


    112、表达式语言(EL)支持哪些运算符?
    答:除了.和[]运算符,EL还提供了:
    - 算术运算符:+、-、*、/或div、%或mod
    - 关系运算符:==或eq、!=或ne、>或gt、>=或ge、<或lt、<=或le
    - 逻辑运算符:&&或and、||或or、!或not
    - 条件运算符:${statement? A : B}(跟Java的条件运算符类似)
    - empty运算符:检查一个值是否为null或者空(数组长度为0或集合中没有元素也返回true)


    113、Java Web开发的Model 1和Model 2分别指的是什么?
    答:Model 1是以页面为中心的Java Web开发,使用JSP+JavaBean技术将页面显示逻辑和业务逻辑处理分开,JSP实现页面显示,JavaBean对象用来保存数据和实现业务逻辑。Model 2是基于MVC(模型-视图-控制器,Model-View-Controller)架构模式的开发模型,实现了模型和视图的彻底分离,利于团队开发和代码复用,如下图所示。


    114、Servlet 3中的异步处理指的是什么?
    答:在Servlet 3中引入了一项新的技术可以让Servlet异步处理请求。有人可能会质疑,既然都有多线程了,还需要异步处理请求吗?答案是肯定的,因为如果一个任务处理时间相当长,那么Servlet或Filter会一直占用着请求处理线程直到任务结束,随着并发用户的增加,容器将会遭遇线程超出的风险,这这种情况下很多的请求将会被堆积起来而后续的请求可能会遭遇拒绝服务,直到有资源可以处理请求为止。异步特性可以帮助应用节省容器中的线程,特别适合执行时间长而且用户需要得到结果的任务,如果用户不需要得到结果则直接将一个Runnable对象交给Executor并立即返回即可。(如果不清楚多线程和线程池的相关内容,请查看前面章节关于多线程和线程池的部分或阅读我的另一篇文章)

    补充:多线程在Java诞生初期无疑是一个亮点,而Servlet单实例多线程的工作方式也曾为其赢得美名,然而技术的发展往往会颠覆我们很多的认知,就如同当年爱因斯坦的相对论颠覆了牛顿的经典力学一般。事实上,异步处理绝不是Serlvet 3首创,如果你了解的话,对Servlet 3的这个重要改进就不以为奇了。

    下面是一个支持异步处理请求的Servlet的例子。

    import java.io.IOException;
    import javax.servlet.AsyncContext;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    @WebServlet(urlPatterns = {"/async"}, asyncSupported = true)
    public class AsyncServlet extends HttpServlet {
      private static final long serialVersionUID = 1L;
      @Override
      public void doGet(HttpServletRequest req,
      HttpServletResponse resp)
          throws ServletException, IOException {
       // 开启Tomcat异步Servlet支持
       req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
       final AsyncContext ctx = req.startAsync();
      // 启动异步处理的上下文
      // ctx.setTimeout(30000);
      ctx.start(new Runnable() {
         @Override
         public void run() {
          // 在此处添加异步处理的代码
          ctx.complete();
         }
       });
     }
    }


    115、如何在基于Java的Web项目中实现文件上传和下载?
    答:在Sevlet 3 以前,Servlet API中没有支持上传功能的API,因此要实现上传功能需要引入第三方工具从POST请求中获得上传的附件或者通过自行处理输入流来获得上传的文件,我们推荐使用Apache的commons-fileupload。
    从Servlet 3开始,文件上传变得无比简单,相信看看下面的例子一切都清楚了。

    上传页面index.jsp:

    <%@ page pageEncoding="utf-8"%>
    <!DOCTYPE html>
    <html>
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <title>Photo Upload</title>
    </head>
    <body>
      <h1>Select your photo and upload</h1>
      <hr/>
      <div style="color:red;font-size:14px;">${hint}</div>
      <form action="UploadServlet" method="post" enctype="multipart/form-data">
        Photo file: <input type="file" name="photo" />
        <input type="submit" value="Upload" />
      </form>
    </body>
    </html>

    支持上传的Servlet:

    package com.jackfrued.servlet;
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.Part;
    @WebServlet("/UploadServlet")
    @MultipartConfig
    public class UploadServlet extends HttpServlet {
     private static final long serialVersionUID = 1L;
     protected void doPost(HttpServletRequest request,
     HttpServletResponse response)
     throws ServletException, IOException {
      // 可以用request.getPart()方法获得名为photo的上传附件
      // 也可以用request.getParts()获得所有上传附件(多文件上传)
      // 然后通过循环分别处理每一个上传的文件
      Part part = request.getPart("photo");
      if (part != null && part.getSubmittedFileName()
     .length() > 0) {
        // 用ServletContext对象的getRealPath()方法获得上传文件夹的绝对路径
        String savePath = request.getServletContext().getRealPath("/upload");
        // Servlet 3.1规范中可以用Part对象的getSubmittedFileName()方法获得上传的文件名
        // 更好的做法是为上传的文件进行重命名(避免同名文件的相互覆盖)
        part.write(savePath + "/" + part.getSubmittedFileName());
        request.setAttribute("hint", "Upload Successfully!");
       } else {
        request.setAttribute("hint", "Upload failed!");
       }
       // 跳转回到上传页面
       request.getRequestDispatcher("index.jsp")
     .forward(request, response);
     }
    }


    116、服务器收到用户提交的表单数据,到底是调用Servlet的doGet()还是doPost()方法?
    答:HTML的<form>元素有一个method属性,用来指定提交表单的方式,其值可以是get或post。我们自定义的Servlet一般情况下会重写doGet()或doPost()两个方法之一或全部,如果是GET请求就调用doGet()方法,如果是POST请求就调用doPost()方法,那为什么为什么这样呢?我们自定义的Servlet通常继承自HttpServlet,HttpServlet继承自GenericServlet并重写了其中的service()方法,这个方法是Servlet接口中定义的。HttpServlet重写的service()方法会先获取用户请求的方法,然后根据请求方法调用doGet()、doPost()、doPut()、doDelete()等方法,如果在自定义Servlet中重写了这些方法,那么显然会调用重写过的(自定义的)方法,这显然是对模板方法模式的应用(如果不理解,请参考阎宏博士的《Java与模式》一书的第37章)。当然,自定义Servlet中也可以直接重写service()方法,那么不管是哪种方式的请求,都可以通过自己的代码进行处理,这对于不区分请求方法的场景比较合适。


    117、JSP中的静态包含和动态包含有什么区别?
    答:静态包含是通过JSP的include指令包含页面,动态包含是通过JSP标准动作<jsp:forward>包含页面。静态包含是编译时包含,如果包含的页面不存在则会产生编译错误,而且两个页面的"contentType"属性应保持一致,因为两个页面会合二为一,只产生一个class文件,因此被包含页面发生的变动再包含它的页面更新前不会得到更新。动态包含是运行时包含,可以向被包含的页面传递参数,包含页面和被包含页面是独立的,会编译出两个class文件,如果被包含的页面不存在,不会产生编译错误,也不影响页面其他部分的执行。代码如下所示:

    <%-- 静态包含 --%> <%@ include file="..." %> <%-- 动态包含 --%> <jsp:include page="...">    <jsp:param name="..." value="..." /> </jsp:include>


        118、Servlet中如何获取用户提交的查询参数或表单数据?
        答:可以通过请求对象(HttpServletRequest)的getParameter()方法通过参数名获得参数值。如果有包含多个值的参数(例如复选框),可以通过请求对象的getParameterValues()方法获得。当然也可以通过请求对象的getParameterMap()获得一个参数名和参数值的映射(Map)。


        119、Servlet中如何获取用户配置的初始化参数以及服务器上下文参数?
        答:可以通过重写Servlet接口的init(ServletConfig)方法并通过ServletConfig对象的getInitParameter()方法来获取Servlet的初始化参数。可以通过ServletConfig对象的getServletContext()方法获取ServletContext对象,并通过该对象的getInitParameter()方法来获取服务器上下文参数。当然,ServletContext对象也在处理用户请求的方法(如doGet()方法)中通过请求对象的getServletContext()方法来获得。


        120、如何设置请求的编码以及响应内容的类型?
        答:通过请求对象(ServletRequest)的setCharacterEncoding(String)方法可以设置请求的编码,其实要彻底解决乱码问题就应该让页面、服务器、请求和响应、Java程序都使用统一的编码,最好的选择当然是UTF-8;通过响应对象(ServletResponse)的setContentType(String)方法可以设置响应内容的类型,当然也可以通过HttpServletResponsed对象的setHeader(String, String)方法来设置。

        说明:现在如果还有公司在面试的时候问JSP的声明标记、表达式标记、小脚本标记这些内容的话,这样的公司也不用去了,其实JSP内置对象、JSP指令这些东西基本上都可以忘却了,关于Java Web开发的相关知识,可以看一下我的,上面有完整的知识点的罗列。想了解如何实现自定义MVC框架的,可以看一下我的。


        您可能也对以下帖子感兴趣

        文章有问题?点此查看未经处理的缓存